module top #(parameter depth = 16,
             parameter width = 16)
            (input wr_clk,
             input rd_clk,
             input rst_n,
             input wr_en,
             input rd_en,
             input [width-1:0] data_in,
             output [width-1:0] data_out,
             output fall,
             output empty);
    
    reg [width-1:0] mem[depth-1:0];
    reg [4:0] waddr;
    wire [4:0] waddr_gray;
    reg [4:0] waddr_w2r1;
    reg [4:0] waddr_w2r2;
    
    reg [4:0] raddr;
    wire [4:0] raddr_gray;
    reg [4:0] raddr_r2w1;
    reg [4:0] raddr_r2w2;
    
    reg [width-1:0] temp_out;
    
    // 写指�???????
    always @(posedge wr_clk or negedge rst_n) begin
        if (!rst_n)
            waddr <= 5'b00000;
        else if (wr_en)
            waddr <= waddr+1'b1;
        else
            waddr <= waddr;
    end
    // 写指针格雷码
    assign waddr_gray = (waddr>>1)^waddr;
    // 写指针同步到读时�???????
    always @(posedge rd_clk or negedge rst_n) begin
        if (!rst_n)
            {waddr_w2r2,waddr_w2r1} <= {5'b00000,5'b00000};
        else
            {waddr_w2r2,waddr_w2r1} <= {waddr_w2r1,waddr_gray};
    end
    
    // 读指�???????
    always @(posedge rd_clk or negedge rst_n) begin
        if (!rst_n)
            raddr <= 5'b00000;
        else if (rd_en)
            raddr <= raddr+1;
        else
            raddr <= raddr;
    end
    
    //读指针格雷码
    assign raddr_gray = (raddr>>1)^raddr;
    
    //读指针同步到写指�???????
    always @(posedge wr_clk or negedge rst_n) begin
        if (!rst_n)
            {raddr_r2w2,raddr_r2w1} <= {2{5'b00000}};
        else
            {raddr_r2w2,raddr_r2w1} <= {raddr_r2w1,raddr_gray};
    end
    
    // 写数�???????
    always @(posedge wr_clk)
    begin
        if (wr_en&(full == 0))
            mem[waddr] <= data_in;
            end
        
        // 读数
        assign data_out = temp_out;
        always @(posedge rd_clk) begin
            if (!rst_n)
                temp_out <= {width{1'b0}};
            else if (rd_en == 1&(empty == 0))
                temp_out <= mem[raddr];
            else
                temp_out <= mem[waddr];
        end
        
        assign empty = (waddr_w2r2 == raddr_gray)?1'b1:1'b0;
        assign full  = ({~(raddr_r2w2[4:3]),raddr_r2w2[2:0]} == {waddr_gray}?1'b1:1'b0);
        
        endmodule
